package com.example.studyPlatform.controller.api.kit;

import com.example.studyPlatform.controller.api.protocol.API_STATE;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;

import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.Collectors;

import static com.example.studyPlatform.config.BaseConstant.UNDEFINE;

public class JsonUtils {

    public final static ObjectMapper mapper = new ObjectMapper();

    public static String objectToString(Object obj) {
        try {
            return mapper.writeValueAsString(obj);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static Object mapToBean(Map map, Class clazz) {
        try {
            return mapper.readValue(objectToString(map), clazz);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return null;
    }

    private static List<Field> getAllFields(Object obj){
        Class clazz = obj.getClass();
        List<Field> fields = new ArrayList<>();
        while (clazz!=null){
            fields.addAll(new ArrayList<>(Arrays.asList(clazz.getFields())));
            clazz = clazz.getSuperclass();
        }
        return fields;
    }

    public static Map<String ,Object> toMap(Object obj) {
        Map<String ,Object>map=new HashMap<>();
        for(Field f:getAllFields(obj)){
            try {
                map.put(f.getName(),f.get(obj));
            } catch (IllegalAccessException e) {
                e.printStackTrace();
                return null;
            }
        }
        return map;
    }

    public static Map<String,Object> beanToMap(Object obj) {
        try {
            return mapper.readValue(objectToString(obj), Map.class);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return null;
    }

    static {
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    }

    public static String getString(JsonNode json, String path) {
        json = json.at(path);
        if (json.toString().equals("") || json.toString().equals("null"))
            return null;
        return json.asText();
    }

    public static String getString(JsonNode json, String path, String defaultValue) {
        return json.at(path).asText(defaultValue);
    }

    public static Boolean getBoolean(JsonNode json, String path) {
        json = json.at(path);
        if (json.toString().equals("") || json.toString().equals("null"))
            return null;
        return json.asBoolean();
    }

    public static Boolean getBoolean(JsonNode json, String path, boolean defaultValue) {
        return json.at(path).asBoolean(defaultValue);
    }

    public static Integer getInteger(JsonNode json, String path) {
        json = json.at(path);
        if (json.toString().equals("") || json.toString().equals("null"))
            return null;
        return json.asInt();
    }

    public static Integer getInteger(JsonNode json, String path, int defaultValue) {
        return json.at(path).asInt(defaultValue);
    }

    public static JsonNode getJsonNode(JsonNode json, String path) {
        return json.at(path);
    }

    public static ObjectNode toJson(API_STATE state) {
        return toJson(state, UNDEFINE);
    }

    public static ObjectNode toJson(API_STATE state, Object result) {
        return toJsonAttachRemark(state, UNDEFINE, result);
    }

    public static ObjectNode toJsonAttachRemark(API_STATE state, String remark) {
        return toJsonAttachRemark(state, remark, UNDEFINE);
    }

    public static ObjectNode toJsonAttachRemark(API_STATE state, String remark, Object result) {
        ObjectNode res = mapper.createObjectNode();
        res.put("success", state.code == 200);
        res.put("code", state.code);
        res.put("message", state.message);
        res.put("remark", remark);
        if (state.code == 200) {
            if (result instanceof JsonNode) {
                res.set("result", (JsonNode) result);
            } else {
                res.putPOJO("result", result);
            }
        } else {
            res.put("result", UNDEFINE);
        }
        return res;
    }

}
